/*
 * Copyright (c) 2022 Talkweb Co., Ltd.
 *
 * HDF is dual licensed: you can use it either under the terms of
 * the GPL, or the BSD license, at your option.
 * See the LICENSE file in the root of this repository for complete details.
 */


#include "hdf_device_desc.h"  
#include "hdf_log.h"   
#include "gpio_if.h"
#include "osal_irq.h"
#include "osal_time.h"

#define HDF_LOG_TAG "gpio_test_drv_log"   

#define LED_ON 123
#define LED_OFF 456

#define LED_PIN   6   // GPIO0_6,  0 * 8 + 6 = 6
#define IRQ_PIN   30  // GPIO3_6,  3 * 8 + 6 = 30

static int32_t init_flag = 0;

static int32_t led_on(void)
{
    if (GpioWrite(LED_PIN, 0) != HDF_SUCCESS){
        HDF_LOGE("GpioWrite: LED_PIN failed\n");
        return HDF_FAILURE;
    } 
    return HDF_SUCCESS;
}

static int32_t led_off(void)
{
    if (GpioWrite(LED_PIN, 1) != HDF_SUCCESS){
        HDF_LOGE("GpioWrite: LED_PIN failed\n");
        return HDF_FAILURE;
    } 
    return HDF_SUCCESS;
}


int32_t gpio_test_irq(uint16_t gpio, void *data)
{
    uint16_t irq_pin_val = 0;

    if (GpioDisableIrq(gpio) != HDF_SUCCESS) {
        HDF_LOGE("%s: disable irq failed", __func__);
        return HDF_FAILURE;
    }

    if(GpioRead(IRQ_PIN, &irq_pin_val) != HDF_SUCCESS)
        return HDF_FAILURE;
    if(irq_pin_val == 0)
    {
        led_off();
        HDF_LOGE("irq pin val is low");
    }else{
        led_on();
        HDF_LOGE("irq pin val is high");
    }        

    if (GpioEnableIrq(gpio) != HDF_SUCCESS) {
        HDF_LOGE("%s: enable irq failed", __func__);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

static int32_t GpioSetup()
{
    if (GpioSetDir(LED_PIN, GPIO_DIR_OUT) != HDF_SUCCESS){
        HDF_LOGE("GpioSerDir: LED_PIN failed\n");
        return HDF_FAILURE;
    }

    if (GpioSetDir(IRQ_PIN, GPIO_DIR_IN) != HDF_SUCCESS){
        HDF_LOGE("GpioSerDir: IRQ_PIN failed\n");
        return HDF_FAILURE;
    }

    if (GpioDisableIrq(IRQ_PIN) != HDF_SUCCESS) {
        HDF_LOGE("%s: disable irq failed", __func__);
        return HDF_FAILURE;
    }

    if (GpioSetIrq(IRQ_PIN, OSAL_IRQF_TRIGGER_RISING | OSAL_IRQF_TRIGGER_FALLING, gpio_test_irq, NULL) != HDF_SUCCESS) {
        HDF_LOGE("GpioSetIrq: failed\n");
        return HDF_FAILURE;
    }

    if (GpioEnableIrq(IRQ_PIN) != HDF_SUCCESS) {
        HDF_LOGE("GpioEnableIrq: failed\n");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t HdfGPIODriverDispatch(struct HdfDeviceIoClient *client, int32_t id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    uint16_t led_pin_val = 0;

    if (client == NULL || client->device == NULL){
        HDF_LOGE("Led driver device is NULL");
        return HDF_ERR_INVALID_OBJECT;
    }

    if(init_flag == 0){
        if(GpioSetup() != HDF_SUCCESS)
            return HDF_FAILURE;
        init_flag = 1;
    }
    
    if (id == LED_ON) {  
        const char *readData = HdfSbufReadString(data);
        if (readData != NULL) {
            HDF_LOGE("%s: read data is: %s", __func__, readData); 
            if(led_on() != HDF_SUCCESS)
                return HDF_FAILURE;
        }
        GpioRead(LED_PIN, &led_pin_val);
        if (!HdfSbufWriteString(reply, "ledon")) {
            HDF_LOGE("%s: %d reply string fail", __func__, __LINE__);  
            return HDF_FAILURE;
        }
        if (!HdfSbufWriteUint16(reply, led_pin_val)) {
            HDF_LOGE("%s: %d reply uint16 fail", __func__, __LINE__);
            return HDF_FAILURE;
        }
    }else if(id == LED_OFF) {     
        const char *replyData = HdfSbufReadString(data);
        if (replyData != NULL) {
            HDF_LOGE("%s: read data is: %s", __func__, replyData); 
            if(led_off() != HDF_SUCCESS)
                return HDF_FAILURE;
        }
        GpioRead(LED_PIN, &led_pin_val);           
        if (!HdfSbufWriteString(reply, "ledoff")) {
            HDF_LOGE("%s: reply1 string fail", __func__);
        }
        if (!HdfSbufWriteUint16(reply, led_pin_val)) {
            HDF_LOGE("%s: reply1 int32 fail", __func__);
        }
        if(HdfDeviceSendEvent(client->device, id, reply) != HDF_SUCCESS)
            return HDF_FAILURE;
    }else{
        HDF_LOGE("%s: error id", __func__);
        return HDF_FAILURE;
    }       
    
    return HDF_SUCCESS;
}

int32_t HdfGPIODriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        return HDF_FAILURE;
    }
    static struct IDeviceIoService gpioTestService = {
        .Dispatch = HdfGPIODriverDispatch,
    };
    deviceObject->service = &gpioTestService;
    HDF_LOGD("GPIO driver bind success");
    return HDF_SUCCESS;
}

int32_t HdfGPIODriverInit(struct HdfDeviceObject *deviceObject)
{    
    HDF_LOGD("GPIO driver Init success");
    return HDF_SUCCESS;
}

void HdfGPIODriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("GPIO driver release success");
    return;
}

struct HdfDriverEntry g_GPIODriverEntry = {
    .moduleVersion = 1,
    .moduleName = "GPIO_TEST_DRIVER",
    .Bind = HdfGPIODriverBind,
    .Init = HdfGPIODriverInit,
    .Release = HdfGPIODriverRelease,
};

HDF_INIT(g_GPIODriverEntry);